package org.summerframework.component.quartz.config;

import org.summerframework.component.quartz.QuartzStateEnum;
import org.summerframework.component.quartz.annotation.QuartzJob;
import org.summerframework.core.util.SpringContextUtil;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
import org.springframework.boot.autoconfigure.quartz.QuartzProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

import static org.quartz.Trigger.TriggerState.*;

/**
 * @author 石超
 * @version v1.0.0
 */
@Configuration
@AutoConfigureAfter({QuartzAutoConfiguration.class})
@EnableConfigurationProperties(QuartzProperties.class)
public class QuartzInitConfig implements BeanFactoryAware, InitializingBean {


    private ListableBeanFactory beanFactory;

    private Scheduler scheduler;

    @Resource
    private QuartzProperties quartzProperties;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (ListableBeanFactory) beanFactory;
    }

    @Bean
    public static QuartzPostProcessor quartzPostProcessor() {
        return new QuartzPostProcessor();
    }

    @Autowired(required = false)
    public void setScheduler(Scheduler scheduler) {
        this.scheduler = scheduler;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (!quartzProperties.isOverwriteExistingJobs()) {
            for (QuartzPostProcessor.QuartzJobDTO quartzJobDTO : QuartzPostProcessor.quartzJobs) {
                final String name = quartzJobDTO.getTriggerName();
                final QuartzJob quartzJob = quartzJobDTO.getQuartzJob();
                final TriggerKey key = TriggerKey.triggerKey(name, quartzJob.group());

                Scheduler scheduler = this.scheduler;

                if (StringUtils.isNotEmpty(quartzJob.scheduler())) {
                    scheduler = SpringContextUtil.getBean(quartzJob.scheduler());
                }

                if(scheduler == null){
                    throw new IllegalArgumentException("scheduler is not null");
                }

                try {
                    if (quartzJobDTO.getMethod().isAnnotationPresent(Deprecated.class)) {
                        scheduler.unscheduleJob(key);
                        continue;
                    }

                    final Trigger trigger = scheduler.getTrigger(key);

                    //清理不正常状态
                    if (trigger instanceof CronTrigger) {
                        CronTrigger cronTrigger = (CronTrigger) trigger;
                        final Trigger.TriggerState triggerState = scheduler.getTriggerState(key);

                        switch (quartzJob.state()) {
                            case NORMAL:
                                if (triggerState != NORMAL || !StringUtils.equals(cronTrigger.getCronExpression(), quartzJob.cron()) || quartzJob.misfireInstruction() != cronTrigger.getMisfireInstruction()) {
                                    scheduler.rescheduleJob(key, beanFactory.getBean(name, Trigger.class));
                                }
                                break;
                            case PAUSED:
                            case BLOCKED:
                            case ERROR:
                                if (triggerState != PAUSED) {
                                    scheduler.pauseTrigger(key);
                                }
                            case NONE:
                                if (triggerState != NONE) {
                                    scheduler.unscheduleJob(key);
                                }
                        }
                    }
                } catch (SchedulerException e) {
                    if (quartzJob.state() == QuartzStateEnum.NONE) {
                        scheduler.unscheduleJob(key);
                    }
                    e.printStackTrace();
                }
            }
        }
    }
}
